/*
    通讯录客户端服务的定义，具有对通讯录操作的所有方法
    1. 添加联系人
    2. 删除联系人
    3. 查看联系人
    4. 查看联系人列表
*/
#pragma once
#include <iostream>
#include <string>
#include <memory>
#include "../common/contacts_expection.hpp"
#include "../common/base_response.pb.h"
#include "../common/add_contacts.pb.h"
#include "../common/httplib.h"

enum PHONYTYPE
{
    MB = 1,
    TEL = 2
};

class ContactsClient
{
public:
    ContactsClient(const std::shared_ptr<httplib::Client>& client_ptr) : 
        _client_ptr(client_ptr)
    {
    }
    
    // 添加联系人
    void AddContacts()
    {
        // 1. 构建请求
        add_contacts::AddContactsRequest request;
        BuildContactsRequest(request);

        try
        {
            // 2. 序列化
            std::string req_str;
            bool ret = request.SerializeToString(&req_str);
            if(!ret) // 序列化失败抛出异常
                throw ContactsException("AddContactsRequest序列化失败");

            // 3. 发起请求
            httplib::Result result = _client_ptr->Post("/contacts", req_str, "application/protobuf");
            if(!result)
            {
                std::string err_desc = "";
                err_desc.append("网络超时, 错误信息: ")
                        .append(httplib::to_string(result.error()));
                throw ContactsException(err_desc);
            }

            // 4. 反序列化
            add_contacts::AddContactsResponse response;
            ret = response.ParseFromString(result->body);
            if(result->status != 200 && !ret)
            {
                // 处理异常
                std::string err_desc = "";
                err_desc.append("Post '/contacts' 处理异常, 状态码: ")
                        .append(std::to_string(result->status))
                        .append("(")
                        .append(result->reason)
                        .append(")");
                throw ContactsException(err_desc);
            }
            else if(result->status != 200)
            {
                // 服务异常
                std::string err_desc = "";
                err_desc.append("Post '/contacts' 服务异常, 状态码: ")
                        .append(std::to_string(result->status))
                        .append("(")
                        .append(result->reason)
                        .append(")")
                        .append(", 错误信息: ")
                        .append(response.base_response().error_desc());
                throw ContactsException(err_desc);

            }
            else if(!response.base_response().success())
            {
                // 结果异常
                std::string err_desc = "";
                err_desc.append("Post '/contacts' 结果异常, ")
                        .append("错误信息: ")
                        .append(response.base_response().error_desc());
                throw ContactsException(err_desc);
            }

            // 4. 输出用户唯一id
            std::cout << "添加成功, 联系人id为: " << response.uid() << std::endl;
        }
        catch(const ContactsException& e)
        {
            std::cout << e.what() << std::endl;
        }
    }

    // 删除联系人
    void DeleteContacts()
    {
    }

    // 查看联系人
    void QueryContacts()
    {
    }


    // 查看联系人列表
    void QueryContactsList()
    {
    }

private:
    // 构建添加联系人请求
    void BuildContactsRequest(add_contacts::AddContactsRequest& request)
    {
        std::cout << "-------------------新增联系⼈-------------------" << std::endl;
        // 1. 姓名
        std::cout << "输入联系人姓名：";
        std::string name;
        getline(std::cin, name);
        request.set_name(name);

        // 2. 年龄
        std::cout << "输入联系人年龄：";
        int age;
        std::cin >> age;
        std::cin.ignore(256, '\n');
        request.set_age(age);

        // 3. 电话
        std::cout << "输入联系人电话(输入回车结束输入): " << std::endl;
        for(int i = 1; ; i++)
        {
            add_contacts::AddContactsRequest_Phone* phone_ptr =  request.add_phone();
            std::cout << "输入第" << i << "个电话号码：";
            std::string number;
            getline(std::cin, number);
            if(number.empty())
                break;
            phone_ptr->set_number(number);

            std::cout << "输入第" << i << "个电话类型(1.移动电话 2.固定电话): ";
            int phone_type;
            std::cin >> phone_type;
            std::cin.ignore(256, '\n');
            switch(phone_type)
            {
            case PHONYTYPE::MB:
                phone_ptr->set_type(add_contacts::AddContactsRequest_Phone_PhoneType_MB);
                break;
            case PHONYTYPE::TEL:
                phone_ptr->set_type(add_contacts::AddContactsRequest_Phone_PhoneType_TEL);
                break;
            default:
                std::cout << "非法选择，使用默认值" << std::endl;
            }
        }
    }

    // // 打印所有
    // void PrintContacts(const addressbook::AddressBook& addressBook)
    // {
    //     int n = addressBook.contacts_size();
    //     for(int i = 0; i < n; i++)
    //     {
    //         const addressbook::Contacts& ct = addressBook.contacts(i);  
    //         std::cout << "-----------------联系人" << i+1 << "-----------------" << std::endl;
    //         std::cout << "姓名：" << ct.name() << std::endl;
    //         std::cout << "年龄：" << ct.age() << std::endl;
    //         int m = ct.phones_size();
    //         for(int j = 0; j < m; j++)
    //         {
    //             const addressbook::Contacts_Phone& phone = ct.phones(j);
    //             std::cout << "电话" << j+1 << ": " << phone.number() 
    //                 << "(" << phone.Type_Name(phone.type()) << ")" << std::endl; // Type_Name可以将枚举值转换为值名
    //             // 如果枚举值没有被设置，protobuf会使用默认值0填充
    //         }

    //         // 注意：下面的Is()判断是否是指定message类型，以及UnpackTo()解析函数是由Any类型提供的，不是Contacts类型提供的
    //         if(ct.has_address() && ct.address().Is<addressbook::Address>()) // 判断地址中是否有数据 && 数据是否是Address类型
    //         {
    //             addressbook::Address addr;
    //             ct.address().UnpackTo(&addr); // 将数据从Any类型解析到对应的类型
    //             std::cout << "家庭地址：" << addr.home_address() << std::endl;
    //             std::cout << "单位地址：" << addr.unit_address() << std::endl;
    //         }

    //         // 利用switch判断联系方式是哪种，不用ct.has_qq()或ct.has_wechat()
    //         addressbook::Contacts::ContactInfoCase contactInfoType = ct.contact_info_case(); // 此函数会返回一个枚举类型
    //         switch(contactInfoType)
    //         {
    //         case addressbook::Contacts::ContactInfoCase::kQq:
    //             std::cout << "QQ: " << ct.qq() << std::endl;
    //             break;
    //         case addressbook::Contacts::ContactInfoCase::kWechat:
    //             std::cout << "微信：" << ct.wechat() << std::endl;
    //             break;
    //         case addressbook::Contacts::ContactInfoCase::CONTACT_INFO_NOT_SET:
    //             break;
    //         }

    //         if(ct.commits_size())
    //         {
    //             std::cout << "备注信息：" << std::endl;
    //         }
    //         for(auto it = ct.commits().begin(); it != ct.commits().end(); it++)
    //         {
    //             std::cout << "  " << it->first << ": " << it->second << std::endl;
    //         }
    //     }
    // }

private:
    std::shared_ptr<httplib::Client> _client_ptr;
};